// 引入 Node.js 内置的加密模块，用于生成安全的随机字节
const crypto = require('crypto');

class CodeGenerator {
    constructor() {
        // 记录上一次尝试生成短码的时间，用于速率限制
        this.lastAttemptTime = 0;
        // 记录当前一秒内的尝试次数，用于速率限制
        this.attemptCount = 0;
        // 每秒最大尝试次数限制，防止接口被暴力调用
        this.MAX_ATTEMPTS_PER_SECOND = 50;
    }

    /**
     * 生成指定长度的随机短码
     * @param {number} length - 短码长度，默认为 6 位
     * @returns {string} 返回生成的随机短码
     */
    generateRandomCode(length = 6) {
        // 定义可用的字符集，包括大小写字母和数字
        const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        let result = '';

        // 使用加密安全的随机字节生成器生成随机字节数组
        const randomBytes = crypto.randomBytes(length);

        // 将随机字节映射到字符集上，生成短码
        for (let i = 0; i < length; i++) {
            result += chars[randomBytes[i] % chars.length];
        }

        return result;
    }

    /**
     * 生成数据库中唯一的短码
     * @param {object} connection - 数据库连接对象（例如 mysql2 的连接实例）
     * @param {number} maxAttempts - 最大尝试次数，默认为 10 次
     * @returns {Promise<string>} 返回唯一短码
     * @throws {Error} 如果无法生成唯一短码，则抛出错误
     */
    async generateUniqueShortCode(connection, maxAttempts = 10) {
        const startTime = Date.now(); // 记录开始时间，用于性能监控

        // 速率限制逻辑：每秒最多尝试 MAX_ATTEMPTS_PER_SECOND 次
        const now = Date.now();
        if (now - this.lastAttemptTime < 1000) {
            this.attemptCount++;
            if (this.attemptCount > this.MAX_ATTEMPTS_PER_SECOND) {
                // 如果超过速率限制，则等待剩余时间
                await new Promise(resolve => setTimeout(resolve, 1000 - (now - this.lastAttemptTime)));
                this.attemptCount = 0;
            }
        } else {
            // 超过一秒，重置计数器
            this.attemptCount = 0;
        }
        this.lastAttemptTime = now;

        let attempts = 0; // 当前已尝试次数
        let codeLength = 6; // 初始短码长度为 6
        const triedCodes = new Set(); // 记录已尝试过的短码，避免重复

        // 循环尝试生成唯一短码
        while (attempts < maxAttempts) {
            let code;
            do {
                // 生成随机短码，确保不重复（在当前尝试轮次内）
                code = this.generateRandomCode(codeLength);
            } while (triedCodes.has(code));

            triedCodes.add(code); // 记录已尝试的短码

            try {
                // 查询数据库，检查短码是否已存在
                const [rows] = await connection.query(
                    'SELECT 1 FROM short_links WHERE short_code = ? LIMIT 1',
                    [code]
                );

                // 如果数据库中不存在该短码，则返回成功
                if (rows.length === 0) {
                    return code;
                }

                // 短码已存在，增加尝试次数
                attempts++;
                // 每失败 3 次，增加短码长度，最多增加到 8 位
                codeLength = Math.min(8, 6 + Math.floor(attempts / 3));
            } catch (error) {
                // 如果数据库查询出错，且已到达最大尝试次数，则抛出错误
                if (attempts >= maxAttempts - 1) {
                    metrics.increment('code_generation.failures'); // 记录失败指标
                    // 如果耗时超过 1 秒，记录慢查询指标
                    if (Date.now() - startTime > 1000) {
                        metrics.increment('code_generation.slow_queries');
                    }
                    throw error;
                }
                // 短暂延迟后重试
                await new Promise(resolve => setTimeout(resolve, 100));
            }
        }

        // 超过最大尝试次数，记录失败指标并抛出错误
        metrics.increment('code_generation.failures');
        throw new Error(`无法生成唯一短码，请稍后重试`);
    }
}

// 导出单例实例，方便全局使用
module.exports = new CodeGenerator();